﻿using IronPython.Hosting;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Microsoft.Extensions.Configuration;
using System.IO;

namespace CoreLims.Models.CoreLims
{
    using static System.Net.Mime.MediaTypeNames;
    using Definition = WfDefinition;
    using RuntimeStepSequence = WfRuntimeStepSequence;
    using RuntimeWorkFlow = WfRuntimeWorkFlow;
    using StepSequence = WfStepSequence;

    public sealed class WorkFlow
    {
        // 创建 Scaffold-DbContext "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=E:\我的文档\CoreLims\CoreLims\CoreLims.mdf;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models
        // 同步 Scaffold-DbContext "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=E:\我的文档\CoreLims\CoreLims\CoreLims.mdf;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -Force

        public Definition Definition;
        public List<StepSequence> StepSequenceList;
        public RuntimeWorkFlow RuntimeWorkFlow;
        public List<RuntimeStepSequence> RuntimeStepSequenceList;
        /// <summary>
        /// 附加数据类型
        /// </summary>
        public enum AdditionalType {下一步处理人};

        public readonly string _definitionId;
        private bool _isCreate = false; // 如果是创建新的工作流为 true
        public readonly static CoreLimsContext _dbContext;
        private int _currentLevel = 1;

        public static Func<string> _newId = () => Guid.NewGuid().ToString();
        private static Func<DateTime> _newDateTime = () => DateTime.Now;

        /// <summary>
        /// 创建一个新的工作流空间
        /// </summary>
        public static Func<WorkFlow> CreateWorkFlow = () => new WorkFlow(_newId(), true);

        /// <summary>
        /// 根据传入的 Id 查询，获得已定义的工作流，如果没查询到 Definition 为空
        /// </summary>
        public static Func<string, WorkFlow> GetWorkFlow = (definitionId) => new WorkFlow(definitionId);

        public int CurrentLevel => _currentLevel;
        public void LevelAdd() { _currentLevel++; }
        public void LevelSub() { _currentLevel--; }
        
        static WorkFlow()
        {
            //var connection = "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=C:\\Users\\SLQ\\Desktop\\我的文档\\CoreLims\\core-lims\\CoreLims\\CoreLims.mdf;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False";
            
            //var connection = "Server=LocalHost;Database=CoreLims;MultipleActiveResultSets=True;Integrated Security=False;uid='sa';pwd='123qwe!@#';Trust Server Certificate=true;Connect Timeout=30";
            IConfiguration config = new ConfigurationBuilder()
                            .SetBasePath(Directory.GetCurrentDirectory()) // 设置基础路径为当前目录
                            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                            .Build();
            string connection = config["ConnectionStrings:FileCoreLimsConnection"];

            DbContextOptions<CoreLimsContext> dbContextOption = new DbContextOptions<CoreLimsContext>();
            DbContextOptionsBuilder<CoreLimsContext> dbContextOptionBuilder = new DbContextOptionsBuilder<CoreLimsContext>(dbContextOption);
            _dbContext = new CoreLimsContext(dbContextOptionBuilder.UseSqlServer(connection).Options);
        }

        /// <summary>
        /// 根据传入的 Id 查询，如果没查询到 Definition 为空
        /// </summary>
        /// <param name="definitionId"></param>
        private WorkFlow(string definitionId)
        {
            _definitionId = definitionId;
            Definition = _dbContext.Definition.FirstOrDefault(m => m.Id == definitionId);
        }

        /// <summary>
        /// 利用 Definition 或 RuntimeWorkFlow 自动获取流程定义步骤以及当前已运行的流程步骤。
        /// 如果是利用 Definition 获取流程步骤，则默认是获得最新版本的。如果传入参数，则获取指定版本号的流程步骤。
        /// 如果是利用 RuntimeWorkFlow 来获取对应的流程步骤，则自动获取对应版本的流程步骤。
        /// Definition 或 RuntimeWorkFlow 同时存在的情况下，优先使用 RuntimeWorkFlow 来获取流程步骤定义。
        /// </summary>
        /// <param name="workFlow"></param>
        /// <param name="version">版本号</param>
        /// <returns></returns>
        public void GetAllStepSequenceList(int? version = null)
        {
            if (RuntimeWorkFlow != null)
                StepSequenceList = _dbContext.StepSequence.Where(m => m.DefinitionId == RuntimeWorkFlow.DefinitionId && m.Version == RuntimeWorkFlow.Version).ToList();
            else if (Definition != null)
            {
                if (version == null)
                    StepSequenceList = _dbContext.StepSequence.Where(m => m.DefinitionId == Definition.Id && m.Version == Definition.Version).ToList();
                else
                    StepSequenceList = _dbContext.StepSequence.Where(m => m.DefinitionId == Definition.Id && m.Version == version).ToList();
            }
            if (RuntimeWorkFlow != null)
                RuntimeStepSequenceList = _dbContext.RuntimeStepSequence.Where(m => m.RuntimeWorkFlowId == RuntimeWorkFlow.Id).ToList();
        }

        /// <summary>
        /// 获取运行时流程的同时，会同时获取该运行时版本号对应的流程步骤定义。
        /// 之前未保存的流程定义步骤会被丢弃。
        /// </summary>
        /// <param name="runtimeWorkFlowId"></param>
        internal void getRuntimeWorkFlow(string runtimeWorkFlowId)
        {
            RuntimeWorkFlow = _dbContext.RuntimeWorkFlow.FirstOrDefault(m => m.Id == runtimeWorkFlowId);
            GetAllStepSequenceList();
        }

        public static WorkFlow GetRuntimeWorkFlow(string runtimeWorkFlowId)
        {
            WorkFlow workFlow = WorkFlow.CreateWorkFlow();
            workFlow.getRuntimeWorkFlow(runtimeWorkFlowId);
            return workFlow;
        }

        /// <summary>
        /// 根据 domain 实例，自动获得该 domain 对应的运行时 RuntimeWorkFlow
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="domain"></param>
        /// <returns></returns>
        public static WorkFlow GetRuntimeWorkFlow<T>(T domain) where T : IWorkFlow<T>
        {
            var runtimeWorkFlowId = _dbContext.RuntimeWorkFlow.FirstOrDefault(m => m.DomainId == domain.Id).Id;
            WorkFlow workFlow = WorkFlow.CreateWorkFlow();
            workFlow.getRuntimeWorkFlow(runtimeWorkFlowId);
            return workFlow;
        }

        /// <summary>
        /// 根据 domainName 和 domainId，获得该 domain 对应的运行时 RuntimeWorkFlow
        /// </summary>
        /// <param name="domainName"></param>
        /// <param name="domainId"></param>
        /// <returns></returns>
        public static WorkFlow GetRuntimeWorkFlow(string domainName, string domainId)
        {
            var runtimeWorkFlow = _dbContext.RuntimeWorkFlow.FirstOrDefault(m => m.DomainId == domainId && m.DomainName == domainName);
            if (runtimeWorkFlow == null)
                return null;

            WorkFlow workFlow = WorkFlow.CreateWorkFlow();
            workFlow.getRuntimeWorkFlow(runtimeWorkFlow.Id);
            return workFlow;
        }

        /// <summary>
        /// 测试指定的 Domain 是否存在正在运行的流程，存在返回 true 否则 false
        /// </summary>
        /// <param name="DomainName"></param>
        /// <param name="DomainId"></param>
        /// <returns></returns>
        public static bool ExitWorkFlow(string DomainName, string DomainId)
        {
            var workflow = _dbContext.RuntimeWorkFlow.FirstOrDefault(s => s.DomainName == DomainName && s.DomainId == DomainId && s.Status == "Runing");
            if (workflow == null)
                return false;
            else
                return true;
        }

        private WorkFlow(string definitionId, bool isCreate = true)
        {
            _definitionId = definitionId;
            _isCreate = isCreate;
            Definition = _dbContext.Definition.FirstOrDefault(m => m.Id == "0"); // 返回一个空
        }

        /// <summary>
        /// 根据 DomainId，删除所有相关运行时数据。
        /// </summary>
        /// <param name="DomainId"></param>
        /// <returns></returns>
        public static string RemoveRuntime(string DomainId)
        {
            var wfList = _dbContext.RuntimeWorkFlow.Where(s => s.DomainId== DomainId).ToList();
            foreach (var wf in wfList)
            {
                var stepList = _dbContext.RuntimeStepSequence.Where(s => s.RuntimeWorkFlowId == wf.Id).ToList();
                foreach (var step in stepList)
                    _dbContext.Remove(step);
                _dbContext.Remove(wf);
            }

            return "流程运行时数据删除成功！";
        }

        internal void CreateDefinition(string name, string description,string type, string creatorId)
        {
            Definition = new Definition(_definitionId, name, description, type, creatorId);
        }

        /// <summary>
        /// 保存 Definition 和 StepSequenceList ，每次保存都会使 version+1。
        /// 这样对应于同一个 Definition，可以创建不同版本的步骤序列，并且在运行时不会互相干扰。
        /// </summary>
        public void SaveDefinitionChanges()
        {
            if (Definition != null)
            {
                var definition = _dbContext.Definition.FirstOrDefault(m => m.Id == Definition.Id);
                if (definition == null)
                {
                    _dbContext.Add(Definition);

                    if (StepSequenceList != null)
                    {
                        foreach (var item in StepSequenceList)
                        {
                            _dbContext.Add(item);
                        }
                    }
                }
                else
                {
                    definition.Version++;
                    if (StepSequenceList != null)
                    {
                        foreach (var item in StepSequenceList)
                        {
                            item.Version++;
                            _dbContext.Add(item);
                        }
                    }
                }
            }

            _dbContext.SaveChanges();
        }

        /// <summary>
        /// 创建运行时流程时，会立即将其保存
        /// </summary>
        internal void SaveRuntimeWorkFlow()
        {
            if (!_dbContext.RuntimeWorkFlow.Contains(RuntimeWorkFlow))
                _dbContext.Add(RuntimeWorkFlow);
            _dbContext.SaveChanges();
            RuntimeStepSequenceList = _dbContext.RuntimeStepSequence.Where(m => m.RuntimeWorkFlowId == RuntimeWorkFlow.Id).ToList();
        }

        internal void RemoveRuntimeStep(RuntimeStepSequence runStep)
        {
            _dbContext.RuntimeStepSequence.Remove(runStep);
            _dbContext.SaveChanges();
        }

        /// <summary>
        /// 创建并保存每一运行时步骤
        /// </summary>
        internal Action<List<RuntimeStepSequence>> AddRuntimeWorkFlow
            = (runtimeStepSequenceList) =>
            {
                foreach (var step in runtimeStepSequenceList)
                {
                    _dbContext.Add(step);
                }
                _dbContext.SaveChanges();
            };

        /// <summary>
        /// 返回运行时的步骤,RuntimeStepSequenceId
        /// </summary>
        internal Func<string, RuntimeStepSequence> getRuntimeStep = (Id)
            => _dbContext.RuntimeStepSequence.FirstOrDefault(m => m.Id == Id);

        /// <summary>
        /// 返回定义步骤,StepSequenceId
        /// </summary>
        internal Func<string, StepSequence> getStep = (Id)
            => _dbContext.StepSequence.FirstOrDefault(m => m.Id == Id);
    }

    public static class WorkFlowExtension
    {
        public static WorkFlow NewDefinition(this WorkFlow workFlow, string name, string description, string creatorId, string type)
        {
            workFlow.CreateDefinition(name, description, type, creatorId);
            return workFlow;
        }

        public static WorkFlow AddStepStart(this WorkFlow workFlow, string currentHandlerType = null, string currentHandlerId = null)
        {
            workFlow.StepSequenceList = new List<StepSequence>();
            workFlow.StepSequenceList.Add(new StepSequence(WorkFlow._newId(), workFlow._definitionId, "Single", null,
                "Apply", "发起", currentHandlerType, currentHandlerId, "0", WorkFlow._newId(), workFlow.CurrentLevel, null, null, workFlow.Definition.Version));
            return workFlow;
        }

        public static WorkFlow AddSingleStep(this WorkFlow workFlow, string stepName, string description)
        {
            var index = workFlow.StepSequenceList.Count - 1;
            for (int i = index; i >= 0; i--)
            {
                if (workFlow.StepSequenceList[i].Level == workFlow.CurrentLevel)
                {
                    workFlow.StepSequenceList.Add(new StepSequence(workFlow.StepSequenceList[i].NextId, workFlow._definitionId, "Single", null,
                        stepName, description, null, null, workFlow.StepSequenceList[i].Id, WorkFlow._newId(), workFlow.CurrentLevel, null, null, workFlow.Definition.Version));
                    break;
                }
            }
            return workFlow;
        }

        /// <summary>
        /// 插入一个重复步骤节点
        /// </summary>
        /// <param name="workFlow"></param>
        /// <param name="stepName">这个参数会被后面的 AddLoopChildStart、AddLoopChildEnd 自动获得，用来表示某一循环分支</param>
        /// <param name="description"></param>
        /// <param name="currentHandlerType"></param>
        /// <param name="currentHandlerId"></param>
        /// <returns></returns>
        public static WorkFlow AddLoopStep(this WorkFlow workFlow, string description, string currentHandlerType = null, string currentHandlerId = null)
        {
            var index = workFlow.StepSequenceList.Count - 1;
            for (int i = index; i >= 0; i--)
            {
                if (workFlow.StepSequenceList[i].NextId != null && workFlow.StepSequenceList[i].Level == workFlow.CurrentLevel)
                {
                    workFlow.StepSequenceList.Add(new StepSequence(workFlow.StepSequenceList[i].NextId, workFlow._definitionId, "Loop", null,
                        WorkFlow._newId(), description, currentHandlerType, currentHandlerId, workFlow.StepSequenceList[i].Id, WorkFlow._newId(), workFlow.CurrentLevel, WorkFlow._newId(), null, workFlow.Definition.Version));
                    break;
                }
            }
            return workFlow;
        }

        public static WorkFlow AddJudgeStep(this WorkFlow workFlow, string stepName, string description, string currentHandlerType = null, string currentHandlerId = null)
        {
            var index = workFlow.StepSequenceList.Count - 1;
            for (int i = index; i >= 0; i--)
            {
                if (workFlow.StepSequenceList[i].NextId != null && workFlow.StepSequenceList[i].Level == workFlow.CurrentLevel)
                {
                    workFlow.StepSequenceList.Add(new StepSequence(workFlow.StepSequenceList[i].NextId, workFlow._definitionId, "Judge", null,
                        stepName, description, currentHandlerType, currentHandlerId, workFlow.StepSequenceList[i].Id, null, workFlow.CurrentLevel, null, null, workFlow.Definition.Version));
                    break;
                }
            }
            return workFlow;
        }

        public static WorkFlow AddIocStep(this WorkFlow workFlow, string description, string currentHandlerType = null, string currentHandlerId = null)
        {
            var index = workFlow.StepSequenceList.Count - 1;
            for (int i = index; i >= 0; i--)
            {
                if (workFlow.StepSequenceList[i].NextId != null && workFlow.StepSequenceList[i].Level == workFlow.CurrentLevel)
                {
                    workFlow.StepSequenceList.Add(new StepSequence(workFlow.StepSequenceList[i].NextId, workFlow._definitionId, "Ioc", null,
                        WorkFlow._newId(), description, currentHandlerType, currentHandlerId, workFlow.StepSequenceList[index].Id, WorkFlow._newId(), workFlow.CurrentLevel, null, null, workFlow.Definition.Version));
                    break;
                }
            }
            return workFlow;
        }

        public static WorkFlow AddStepEnd(this WorkFlow workFlow)
        {
            var index = workFlow.StepSequenceList.Count - 1;
            for (int i = index; i >= 0; i--)
            {
                if (workFlow.StepSequenceList[i].NextId != null && workFlow.StepSequenceList[i].Level == workFlow.CurrentLevel)
                {
                    workFlow.StepSequenceList.Add(new StepSequence(workFlow.StepSequenceList[i].NextId, workFlow._definitionId, "Single", null,
                        "End", "结束", null, null, "1", null, workFlow.CurrentLevel, null, null, workFlow.Definition.Version));
                    break;
                }
            }
            return workFlow;
        }

        public static WorkFlow AddLoopChildStart(this WorkFlow workFlow)
        {
            workFlow.LevelAdd();
            var index = workFlow.StepSequenceList.Count - 1;
            workFlow.StepSequenceList.Add(new StepSequence(workFlow.StepSequenceList[index].SubProcess, workFlow._definitionId, "LoopStart", null,
                       workFlow.StepSequenceList[index].StepName, null, null, null, workFlow.StepSequenceList[index].Id,
                       WorkFlow._newId(), workFlow.CurrentLevel, null, null, workFlow.Definition.Version));

            return workFlow;
        }

        public static WorkFlow AddLoopChildEnd(this WorkFlow workFlow)
        {
            var index = workFlow.StepSequenceList.Count - 1;
            var loopStart = new StepSequence();
            for (int a = index; a >= 0; a--) // 找到最近的 loopStart
            {
                if (workFlow.StepSequenceList[a].StepType == "LoopStart" && workFlow.StepSequenceList[a].Level == workFlow.CurrentLevel)
                {
                    loopStart = workFlow.StepSequenceList[a];
                    break;
                }
            }

            for (int i = index; i >= 0; i--)
            {
                if (workFlow.StepSequenceList[i].NextId != null && workFlow.StepSequenceList[i].Level == workFlow.CurrentLevel)
                {
                    workFlow.StepSequenceList.Add(new StepSequence(workFlow.StepSequenceList[i].NextId, workFlow._definitionId, "LoopEnd", null,
                    loopStart.StepName, null, null, null, "1", null, workFlow.CurrentLevel, null, null, workFlow.Definition.Version));
                    break;
                }
            }
            workFlow.LevelSub();
            return workFlow;
        }

        public static WorkFlow AddIocChildStart(this WorkFlow workFlow)
        {
            workFlow.LevelAdd();
            var index = workFlow.StepSequenceList.Count - 1;
            for (int i = index; i >= 0; i--)
            {
                if (workFlow.StepSequenceList[i].NextId != null && workFlow.StepSequenceList[i].Level == workFlow.CurrentLevel - 1)
                {
                    var tempId = WorkFlow._newId();
                    workFlow.StepSequenceList[i].SubProcess = workFlow.StepSequenceList[i].SubProcess == null ? tempId : workFlow.StepSequenceList[i].SubProcess + "," + tempId;

                    workFlow.StepSequenceList.Add(new StepSequence(tempId, workFlow._definitionId, "IocStart", null,
                               workFlow.StepSequenceList[i].StepName, null, null, null, workFlow.StepSequenceList[index].Id,
                               WorkFlow._newId(), workFlow.CurrentLevel, null, null, workFlow.Definition.Version));
                    break;
                }
            }
            return workFlow;
        }

        public static WorkFlow AddIocChildEnd(this WorkFlow workFlow)
        {
            var index = workFlow.StepSequenceList.Count - 1;
            var iocStart = new StepSequence();
            for (int a = index; a >= 0; a--) // 找到最近的 IocStart，为了获取分支标识ID
            {
                if (workFlow.StepSequenceList[a].StepType == "IocStart" && workFlow.StepSequenceList[a].Level == workFlow.CurrentLevel)
                {
                    iocStart = workFlow.StepSequenceList[a];
                    break;
                }
            }

            for (int i = index; i >= 0; i--)
            {
                if (workFlow.StepSequenceList[i].NextId != null && workFlow.StepSequenceList[i].Level == workFlow.CurrentLevel)
                {
                    workFlow.StepSequenceList.Add(new StepSequence(workFlow.StepSequenceList[i].NextId, workFlow._definitionId, "IocEnd", null,
                        iocStart.StepName, null, null, null, "1", null, workFlow.CurrentLevel, null, null, workFlow.Definition.Version));
                    break;
                }
            }
            workFlow.LevelSub();
            return workFlow;
        }

        /// <summary>
        /// 添加一个判断分支
        /// </summary>
        /// <param name="workFlow"></param>
        /// <param name="judgmentConditions">该分支进入的条件</param>
        /// <param name="judgeStepName">判断开始步骤的StepName。 即AddJudgeStep步骤中第一个name参数值</param>
        /// <returns></returns>
        public static WorkFlow AddJudgeChildStart(this WorkFlow workFlow, string judgmentConditions, string judgeStepName)
        {
            var index = workFlow.StepSequenceList.Count - 1;
            for (int i = index; i >= 0; i--)
            {
                if (workFlow.StepSequenceList[i].StepType == "Judge" && workFlow.StepSequenceList[i].Level == workFlow.CurrentLevel && workFlow.StepSequenceList[i].StepName == judgeStepName)
                {
                    var tempId = WorkFlow._newId();
                    workFlow.StepSequenceList[i].NextId = workFlow.StepSequenceList[i].NextId == null ? tempId : workFlow.StepSequenceList[i].NextId + "," + tempId;

                    workFlow.StepSequenceList.Add(new StepSequence(tempId, workFlow._definitionId, "JudgeStart",
                        null, judgeStepName, null, null, null, workFlow.StepSequenceList[i].Id, WorkFlow._newId(), workFlow.CurrentLevel, null, judgmentConditions, workFlow.Definition.Version));
                    break;
                }
            }
            return workFlow;
        }

        /// <summary>
        /// 实际上是添加了一个分支汇聚点
        /// </summary>
        /// <param name="workFlow"></param>
        /// <param name="ConvergencePointName"></param>
        /// <param name="judgeStepName">判断开始步骤的StepName。 即AddJudgeStep步骤中第一个name参数值</param>
        /// <returns></returns>
        public static WorkFlow AddJudgeChildEnd(this WorkFlow workFlow, string ConvergencePointName, string judgeStepName)
        {
            var index = workFlow.StepSequenceList.Count - 1;
            for (int i = index; i >= 0; i--)
            {
                if (workFlow.StepSequenceList[i].Level == workFlow.CurrentLevel)
                {
                    workFlow.StepSequenceList.Add(new StepSequence(workFlow.StepSequenceList[i].NextId, workFlow._definitionId, "JudgeEnd", ConvergencePointName,
                        judgeStepName, null, null, null, workFlow.StepSequenceList[i].Id, WorkFlow._newId(), workFlow.CurrentLevel, null, null, workFlow.Definition.Version));
                    break;
                }
            }
            // 下面找到该分支的起点 judgestart ，然后将 ConvergencePointName 写入到 judgestart 的 convergence 上，供运行时判断。
            var end = workFlow.StepSequenceList[workFlow.StepSequenceList.Count - 1];
            for (int i = index; i >= 0; i--)
            {
                if (end.Level == workFlow.CurrentLevel && end.StepType == "JudgeStart" && end.StepName == judgeStepName)
                {
                    end.ConvergencePoint = ConvergencePointName;
                    break;
                }
                end = workFlow.StepSequenceList[i];
            }
            return workFlow;
        }

        /// <summary>
        /// 如果有多个分支汇聚点，这个函数可以将多个指定的汇聚点汇聚。
        /// </summary>
        /// <param name="workFlow"></param>
        /// <param name="ConvergencePointName"></param>
        /// <returns></returns>
        public static WorkFlow AddConvergenceBranch(this WorkFlow workFlow, string convergencePointName)
        {
            var tempId = WorkFlow._newId(); // 直接添加一步，但是该步骤的前一步ID暂时为空，后面找到后，再来修改。
            var newStep = new StepSequence(tempId, workFlow._definitionId, "Convergence", convergencePointName,
                null, null, null, null, null, WorkFlow._newId(), workFlow.CurrentLevel, null, null, workFlow.Definition.Version);
            workFlow.StepSequenceList.Add(newStep);

            var index = workFlow.StepSequenceList.Count - 2;
            for (int i = index; i >= 0; i--)
            {
                // 倒序搜索时，遇到"Judge"，说明已经搜索最近的判断步骤定义处，此时退出。
                if (workFlow.StepSequenceList[i].Level == workFlow.CurrentLevel && workFlow.StepSequenceList[i].StepType == "Judge")
                    break;

                if (workFlow.StepSequenceList[i].Level == workFlow.CurrentLevel && workFlow.StepSequenceList[i].ConvergencePoint == convergencePointName && workFlow.StepSequenceList[i].StepType == "JudgeEnd")
                {   // 修改找到的步骤的下一步ID和当前这步的前一步ID
                    workFlow.StepSequenceList[i].NextId = tempId;
                    workFlow.StepSequenceList.Last().PreviousId =
                        workFlow.StepSequenceList.Last().PreviousId == null ? workFlow.StepSequenceList[i].Id : workFlow.StepSequenceList.Last().PreviousId + "," + workFlow.StepSequenceList[i].Id;
                }
            }
            return workFlow;
        }

        /// <summary>
        /// 按最外层主工作流打印
        /// </summary>
        /// <param name="workFlow"></param>
        /// <returns></returns>
        public static List<StepSequence> GetMainStepSequenceList(this WorkFlow workFlow)
        {
            if (workFlow.StepSequenceList == null)
                workFlow.GetAllStepSequenceList();

            var tempList = new List<StepSequence>();
            var temp = workFlow.StepSequenceList.Where(w => w.PreviousId == "0").FirstOrDefault();
            while (temp.NextId != null)
            {
                temp = commoonRecursive(workFlow, tempList, temp);
            }
            tempList.Add(temp);
            return tempList;
        }

        /// <summary>
        /// 遍历流程的公共部分
        /// </summary>
        /// <param name="workFlow"></param>
        /// <param name="tempList"></param>
        /// <param name="temp"></param>
        /// <returns></returns>
        private static StepSequence commoonRecursive(WorkFlow workFlow, List<StepSequence> tempList, StepSequence temp)
        {
            if (!temp.NextId.Contains(','))
            {
                tempList.Add(temp);
                temp = workFlow.StepSequenceList.Where(w => w.Id == temp.NextId).FirstOrDefault();
            }
            else
            {
                tempList.Add(temp);
                var judgeNextId = temp.NextId.Split(',');
                foreach (var item in judgeNextId)
                {
                    temp = workFlow.StepSequenceList.Where(w => w.Id == item).FirstOrDefault();
                    tempList.Add(temp);
                    while (temp.NextId != null && !temp.NextId.Contains(','))
                    {
                        if (temp.NextId.Contains(','))
                            recursiveJudgeStep(workFlow, tempList, temp);

                        temp = workFlow.StepSequenceList.Where(w => w.Id == temp.NextId).FirstOrDefault();
                        tempList.Add(temp);
                    }
                }
            }
            return temp;
        }

        /// <summary>
        /// 获得步骤的定义序列
        /// </summary>
        /// <param name="workFlow"></param>
        /// <returns></returns>
        public static List<StepSequence> GetOrderStepSequenceList(this WorkFlow workFlow)
        {
            if (workFlow.Definition == null)
                return null;

            if (workFlow.StepSequenceList == null)
                workFlow.GetAllStepSequenceList();

            var tempList = new List<StepSequence>();
            var temp = workFlow.StepSequenceList.Where(w => w.PreviousId == "0").FirstOrDefault();

            while (temp.NextId != null)
            {
                temp = commoonRecursive(workFlow, tempList, temp);
                if (temp.SubProcess != null)
                    recursiveSubProcessStep(workFlow, tempList, temp);
            }
            tempList.Add(temp);
            return tempList;
        }

        /// <summary>
        /// 递归子流程步骤
        /// </summary>
        /// <param name="workFlow"></param>
        /// <param name="step"></param>
        /// <returns></returns>
        private static List<StepSequence> recursiveSubProcessStep(WorkFlow workFlow, List<StepSequence> tempList, StepSequence step)
        {
            var arrayrId = step.SubProcess.Split(',');
            foreach (var item in arrayrId)
            {
                var temp = workFlow.StepSequenceList.Where(w => w.Id == item).FirstOrDefault();

                while (temp.NextId != null)
                {
                    tempList.Add(temp);
                    if (temp.SubProcess != null)
                        recursiveSubProcessStep(workFlow, tempList, temp);

                    temp = workFlow.StepSequenceList.Where(w => w.Id == temp.NextId).FirstOrDefault();
                }
                tempList.Add(temp);
            }
            return tempList;
        }

        /// <summary>
        /// 递归 判断 步骤的分支
        /// </summary>
        /// <param name="workFlow"></param>
        /// <param name="tempList"></param>
        /// <param name="step"></param>
        /// <returns></returns>
        private static List<StepSequence> recursiveJudgeStep(WorkFlow workFlow, List<StepSequence> tempList, StepSequence step)
        {
            var judgeNextId = step.NextId.Split(',');
            foreach (var item in judgeNextId)
            {
                step = workFlow.StepSequenceList.Where(w => w.Id == item).FirstOrDefault();
                tempList.Add(step);
                while (step.NextId != null && step.NextId.Contains(','))
                {
                    recursiveJudgeStep(workFlow, tempList, step);
                }
            }
            return tempList;
        }

        /// <summary>
        /// 将表达式中的属性转换为值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="workFlow"></param>
        /// <param name="domainName"></param>
        /// <param name="expression"></param>
        /// <returns></returns>
        public static string analysisJudgeExpression(this WorkFlow workFlow, Object domainInstance, string expression)
        {
            string[] temp = expression.Split(' ');
            string re = "";
            if (temp != null)
            {
                int length = temp.Length;
                for (int i = 0; i <= length - 1; i++)
                {
                    if (temp[i].ToLower().Contains("domain"))
                    {
                        var name = temp[i].Split('.');
                        re = re + domainInstance.GetType().GetProperty(name[1]).GetValue(domainInstance, null) + " ";
                    }
                    else
                        re = re + temp[i].ToString() + " ";
                }
            }
            return re;
        }

        /// <summary>
        /// 获取流程运行时序列
        /// </summary>
        /// <param name="workFlow"></param>
        /// <returns></returns>
        public static List<RuntimeStepSequence> getRuntimeStepList(this WorkFlow workFlow)
        {
            var tempList = new List<RuntimeStepSequence>();
            var runStep = workFlow.RuntimeStepSequenceList.Where(w => w.PreviousId == "0").FirstOrDefault();
            tempList.Add(runStep);

            while (runStep != null && runStep.NextId != null)
            {
                runStep = recursiveRuntimeStep(workFlow, tempList, runStep);
            }

            return tempList;
        }

        /// <summary>
        /// 获得当前运行时流程步骤的名称
        /// </summary>
        /// <param name="workFlow"></param>
        /// <returns></returns>
        public static string getCurrentRunStepName(this WorkFlow workFlow)
        {
            if (workFlow.RuntimeWorkFlow != null)
            {
                if (workFlow.RuntimeWorkFlow.Status == "Runing")
                {
                    return workFlow.RuntimeStepSequenceList
                        .FirstOrDefault(m => m.NextId == null && m.StepType == "Single").StepName;
                }
            }
            return null;
        }

        /// <summary>
        /// 获得当前运行步骤ID
        /// </summary>
        /// <param name="workFlow"></param>
        /// <returns></returns>
        public static string getCurrentRunStepID(this WorkFlow workFlow)
        {
            if (workFlow.RuntimeWorkFlow != null)
            {
                if (workFlow.RuntimeWorkFlow.Status == "Runing")
                {
                    return workFlow.RuntimeStepSequenceList
                        .FirstOrDefault(m => m.NextId == null && m.StepType == "Single").Id;
                }
            }
            return null;
        }

        public static RuntimeStepSequence getRunStepByStepname(this WorkFlow workFlow, string StepName)
        {
            if (workFlow.RuntimeWorkFlow != null)
            {
                if (workFlow.RuntimeWorkFlow.Status == "Runing")
                {
                    return workFlow.RuntimeStepSequenceList
                        .FirstOrDefault(m => m.StepName == StepName);
                }
            }
            return null;
        }

        /// <summary>
        /// 获取当前运行步骤的下一步骤的名称
        /// </summary>
        /// <param name="workFlow"></param>
        /// <returns></returns>
        public static string getCurrentNextRunStepName(this WorkFlow workFlow)
        {
            var currenRunStep = workFlow.RuntimeStepSequenceList.FirstOrDefault(m => m.NextId == null && m.StepType == "Single");
            if (currenRunStep.StepName != "End")
                return getNextRunStepSequence(workFlow, currenRunStep)[0].StepName;
            else
                return null;
        }

        /// <summary>
        /// 获取当前步骤的上一步审批步骤,如果流程步骤有跳过，则一直找到有审批人的步骤
        /// </summary>
        /// <param name="workFlow"></param>
        /// <returns></returns>
        public static WfRuntimeStepSequence getCurrentPreviousStep(this WorkFlow workFlow)
        {
            var currenRunStep = workFlow.RuntimeStepSequenceList.FirstOrDefault(m => m.NextId == null && m.StepType == "Single");
            if (currenRunStep.StepName != "Apply")
            {
                var ps = workFlow.RuntimeStepSequenceList.FirstOrDefault(m => m.Id == currenRunStep.PreviousId);
                while(ps.CurrentHandlerId == null && ps.StepName != "Apply")
                {
                    ps = workFlow.RuntimeStepSequenceList.FirstOrDefault(m => m.Id == ps.PreviousId);
                }
                return ps;
            }
            else
                return null;
        }

        /// <summary>
        /// 根据传入的ID序列，一直运行到没有设置跳过的步骤。
        /// 该重载不能用于流程发起步骤。
        /// </summary>
        /// <param name="workFlow"></param>
        /// <param name="skipStepIdList">逗号分隔的ID字符串,这里的ID是流程定义序列的ID</param>
        /// <returns></returns>
        public static void SkipRunWorkFlow(this WorkFlow workFlow, string skipStepIdList, string handlerType, string handlerId)
        {
            if (string.IsNullOrEmpty(skipStepIdList))
                skipStepIdList = "";

            workFlow.RunWorkFlow(null, handlerType, handlerId);
            var currenRunStep = workFlow.RuntimeStepSequenceList.FirstOrDefault(m => m.NextId == null && m.StepType == "Single");
            if (currenRunStep.Description == "结束") // 自动完成最后一步
            {
                workFlow.RunWorkFlow(null, null, null);
                return;
            }

            var nextstepid = getNextRunStepSequence(workFlow, currenRunStep)[0].Id;
            while (skipStepIdList.Contains(currenRunStep.StepSequenceId))
            {
                workFlow.RunWorkFlow();
                currenRunStep = workFlow.RuntimeStepSequenceList.FirstOrDefault(m => m.NextId == null && m.StepType == "Single");
                if (currenRunStep.Description == "结束") // 如果最后一步被设置为跳过，自动完成最后一步
                    workFlow.RunWorkFlow(null, null, null);
                else
                    nextstepid = getNextRunStepSequence(workFlow, currenRunStep)[0].Id;
            }
        }

        private static RuntimeStepSequence recursiveRuntimeStep(this WorkFlow workFlow, List<RuntimeStepSequence> tempList, RuntimeStepSequence temp)
        {
            if (temp.StepType == "Ioc" || temp.StepType == "Loop" || temp.StepType == "Judge")
            {
                var iocList = temp.BranchName.Split(',');
                foreach (var item in iocList)
                {
                    var loop = workFlow.RuntimeStepSequenceList.FirstOrDefault(m => m.Id == item);
                    loop = recursiveRuntimeStep(workFlow, tempList, loop);
                }
            }

            if (temp.NextId == null)
                return temp;

            if (!temp.NextId.Contains(','))
            {
                temp = workFlow.RuntimeStepSequenceList.Where(w => w.Id == temp.NextId).FirstOrDefault();
                tempList.Add(temp);
                temp = recursiveRuntimeStep(workFlow, tempList, temp);
            }
            else
            {
                var judgeNextId = temp.NextId.Split(',');
                foreach (var item in judgeNextId)
                {
                    temp = workFlow.RuntimeStepSequenceList.Where(w => w.Id == item).FirstOrDefault();
                    tempList.Add(temp);
                    temp = recursiveRuntimeStep(workFlow, tempList, temp);
                }
            }
            return temp;
        }

        public static bool getJudgeExpressionValue(this WorkFlow workFlow, string expression)
        {
            var pythonEngine = Python.CreateEngine();
            //var script = pythonEngine.CreateScriptSourceFromFile(@"C:\Users\sunli\Desktop\WorkFlow\WorkFlow\JudgeExpression.py");
            //var script = pythonEngine.CreateScriptSourceFromFile(@"E:\我的文档\CoreLims\CoreLims\Domain\WorkFlow\JudgeExpression.py");
            var dbContext = new CoreLimsContext();
            var path = Common.getGlobalKeyValue(dbContext, "WorkFlow_pyPath");
            var script = pythonEngine.CreateScriptSourceFromFile(path);
            var code = script.Compile();
            var scope = pythonEngine.CreateScope();
            var excuteResult = code.Execute(scope); //返回值

            var _func = scope.GetVariable("JudgeExpression");

            return (bool)_func(expression);
        }

        /// <summary>
        /// 根据已经定义的流程ID值创建一个运行时流程，创建的新流程总是最新版本的
        /// </summary>
        /// <param name="createrId">创建者ID</param>
        /// <param name="createrType">创建者类型</param>
        /// <param name="status">状态，默认值为 Draft</param>
        public static WorkFlow CreateRuntimeWorkFlow<T>(this WorkFlow workFlow, T domain, string createrId = null, string createrType = null) where T : IWorkFlow<T>
        {
            if (workFlow.Definition != null)
                workFlow.RuntimeWorkFlow = new RuntimeWorkFlow(workFlow._definitionId, createrType, createrId, domain.GetType().Name,
                    domain.GetType().Assembly.GetName().Name, domain.GetType().Namespace, domain.Id, workFlow.Definition.Version);
            workFlow.SaveRuntimeWorkFlow();
            return workFlow;
        }

        public static WorkFlow GetRuntimeWorkFlow(this WorkFlow workFlow, string runtimeWorkFlowId)
        {
            workFlow.getRuntimeWorkFlow(runtimeWorkFlowId);
            return workFlow;
        }

        /// <summary>
        /// runtimeWorkFlowId, stepSequence, previousId, nextId
        /// </summary>
        public static Func<string, StepSequence, string, string, RuntimeStepSequence> ConvertStepToRuntimeStep
            = (runtimeWorkFlowId, stepSequence, previousId, nextId) =>
            {
                return new RuntimeStepSequence(runtimeWorkFlowId, stepSequence, previousId, nextId);
            };

        /// <summary>
        /// 运行 RuntimeWorkFlow,以单步方式运行一次向前推进一步。
        /// </summary>
        /// <param name="workFlow"></param>
        /// <param name="runtimeStepId">需要运行的步骤ID</param>
        /// <param name="handlerType">运行该步骤的用户类型</param>
        /// <param name="handlerId">运行该步骤的用户Id</param>
        public static void RunWorkFlow(this WorkFlow workFlow, string runtimeStepId = null, string handlerType = null, string handlerId = null, string additionalType = null, string additionalData = null, string Suggestion = null)
        {
            if (workFlow.RuntimeWorkFlow != null)
            {
                if (workFlow.RuntimeWorkFlow.Status == "Finish")
                    return;

                if (workFlow.RuntimeWorkFlow.Status == "Runing")
                {
                    var currenRunStep = new RuntimeStepSequence();
                    if (runtimeStepId == null)
                        currenRunStep = workFlow.RuntimeStepSequenceList.FirstOrDefault(m => m.NextId == null && m.StepType == "Single");
                    else
                        currenRunStep = workFlow.RuntimeStepSequenceList.FirstOrDefault(m => m.Id == runtimeStepId);

                    if (currenRunStep != null)
                        Runing(workFlow, currenRunStep, handlerType, handlerId, additionalType, additionalData, Suggestion);
                    return;
                }

                if (workFlow.RuntimeWorkFlow.Status == "Draft") // 这段不能提到前面，否则报错。
                    StartWorkFlow(workFlow, handlerId, handlerType);
            }
        }

        private static void Runing(WorkFlow workFlow, RuntimeStepSequence currenRunStep, string handlerType = null, string handlerId = null, string additionalType = null, string additionalData = null, string Suggestion = null)
        {
            RunCurrentRunStep(workFlow, currenRunStep, handlerType, handlerId, additionalType, additionalData, Suggestion);
            var nextStepList = getNextRunStepSequence(workFlow, currenRunStep);

            string nextIds;
            var runNextStepList = StepConvertToRunstep(workFlow, nextStepList, currenRunStep.Id, out nextIds);

            FollowUpProcessing(workFlow, currenRunStep, runNextStepList, nextIds);
            workFlow.AddRuntimeWorkFlow(runNextStepList);
            workFlow.getRuntimeWorkFlow(workFlow.RuntimeWorkFlow.Id); // 刷新列表

            if (nextStepList.Count != 0 && nextStepList[0].StepType != "Single")
            {
                foreach (var item in runNextStepList)
                {
                    workFlow.RunWorkFlow(runtimeStepId: item.Id);
                }
            }
        }

        /// <summary>
        /// 运行当前或指定步骤
        /// </summary>
        /// <param name="workFlow"></param>
        /// <param name="currenRunStep"></param>
        /// <param name="handlerType"></param>
        /// <param name="handlerId"></param>
        private static void RunCurrentRunStep(WorkFlow workFlow, RuntimeStepSequence currenRunStep, string handlerType, string handlerId, string additionalType = null, string additionalData = null, string Suggestion = null)
        {
            currenRunStep.HandlingTime = DateTime.Now;
            currenRunStep.CurrentHandlerType = handlerType;
            currenRunStep.CurrentHandlerId = handlerId;
            if (handlerId != null)
                currenRunStep.Status = "正常";
            else
                currenRunStep.Status = "自动";
            currenRunStep.AdditionalType = additionalType;
            currenRunStep.AdditionalData = additionalData;
            currenRunStep.Suggestion = Suggestion;
        }

        /// <summary>
        /// 定义步骤转换为运行时步骤
        /// </summary>
        /// <param name="workFlow"></param>
        /// <param name="stepList">需要转换的定义步骤序列</param>
        /// <param name="nextIds">转换后的Id集合，供写入到当前运行步骤上</param>
        /// <returns></returns>
        private static List<RuntimeStepSequence> StepConvertToRunstep(WorkFlow workFlow, List<StepSequence> stepList, string currentRunStepId, out string nextIds)
        {
            var reList = new List<RuntimeStepSequence>();
            StringBuilder ids = new StringBuilder();

            foreach (var step in stepList)
            {
                workFlow.RuntimeWorkFlow.UpdataTime = DateTime.Now;

                var temp = ConvertStepToRuntimeStep(workFlow.RuntimeWorkFlow.Id, step, currentRunStepId, null);
                temp.RecordTime = DateTime.Now;
                if (temp.StepType == "Single")
                    temp.Status = "待处理";
                else
                    temp.Status = "自动";
                temp.NextId = null;

                ids.Append(temp.Id + ",");
                reList.Add(temp);
            }

            if (ids.Length != 0)
                ids.Remove(ids.Length - 1, 1);
            nextIds = ids.ToString();

            return reList;
        }

        /// <summary>
        /// 对 当前插入步骤 或 当前执行步骤 的后续处理
        /// </summary>
        /// <param name="workFlow"></param>
        /// <param name="currenRunStep">当前运行的步骤</param>
        /// <param name="runNextStepList">后续运行步骤</param>
        /// <param name="nextIds">后续运行步骤Id字符串集合</param>
        private static void FollowUpProcessing(WorkFlow workFlow, RuntimeStepSequence currenRunStep, List<RuntimeStepSequence> runNextStepList, string nextIds)
        {
            if (runNextStepList.Count == 0)
                return;

            if (runNextStepList[0].StepName == "End" && runNextStepList[0].StepType == "Single")
            {
                currenRunStep.NextId = nextIds;
                runNextStepList[0].Status = "自动";
                workFlow.RuntimeWorkFlow.Status = "Finish";
                workFlow.RuntimeWorkFlow.UpdataTime = DateTime.Now;
                return;
            }

            if (runNextStepList[0].StepType == "Ioc" || runNextStepList[0].StepType == "Loop" || runNextStepList[0].StepType == "Judge")
            {
                currenRunStep.NextId = nextIds;
                return;
            }

            if (runNextStepList[0].StepType == "IocStart" && runNextStepList[0].StepType == "LoopStart" && runNextStepList[0].StepType == "JudgeStart")
            {
                currenRunStep.BranchName = nextIds;
                return;
            }

            if (runNextStepList[0].StepType == "IocEnd")
            {
                currenRunStep.NextId = nextIds;
                return;
            }

            if (runNextStepList[0].StepType == "LoopEnd")
            {
                var pre = workFlow.RuntimeStepSequenceList.FirstOrDefault(m => m.Id == currenRunStep.PreviousId);
                while (pre.PreviousId != "0") // 倒序找到 loopstart
                {
                    if (pre.StepType == "LoopStart" && pre.Level == runNextStepList[0].Level)
                    {
                        runNextStepList[0].StepName = pre.StepName;
                        if (currenRunStep.StepType != "LoopEnd")
                            currenRunStep.NextId = nextIds;
                        break;
                    }
                    pre = workFlow.RuntimeStepSequenceList.FirstOrDefault(m => m.Id == pre.PreviousId);
                }
                return;
            }

            if (currenRunStep.StepType == "LoopEnd")
            {
                var loopStart = workFlow.RuntimeStepSequenceList.FirstOrDefault(m => m.StepType == "LoopStart" && m.StepName == currenRunStep.StepName);
                var loop = workFlow.RuntimeStepSequenceList.FirstOrDefault(m => m.Id == loopStart.PreviousId);
                loop.NextId = runNextStepList[0].Id;
                return;
            }

            if (currenRunStep.StepType == "Loop" || currenRunStep.StepType == "Ioc" || currenRunStep.StepType == "Judge")
            {
                currenRunStep.BranchName = nextIds;
                return;
            }

            if (runNextStepList[0].StepType == "JudgeEnd")
            {
                currenRunStep.NextId = nextIds;
                return;
            }

            if (runNextStepList[0].StepType == "Convergence")
            {
                var judgeStart = workFlow.RuntimeStepSequenceList.FirstOrDefault(m => m.StepType == "JudgeStart" && m.BranchName == currenRunStep.BranchName && m.Level == currenRunStep.Level);
                var judge = workFlow.RuntimeStepSequenceList.FirstOrDefault(m => m.Id == judgeStart.PreviousId);
                if (string.IsNullOrEmpty(judge.NextId))
                    judge.NextId = runNextStepList[0].Id;
                else
                    judge.NextId = judge.NextId + "," + runNextStepList[0].Id;
                return;
            }

            if (runNextStepList[0].StepType == "Single") // 这个判断要放到最后
            {
                currenRunStep.NextId = nextIds;
                return;
            }
        }

        /// <summary>
        /// 开始运行第一步
        /// </summary>
        /// <param name="workFlow"></param>
        /// <param name="nextStepList"></param>
        private static void StartWorkFlow(WorkFlow workFlow, string UserId = null, string UserName = null)
        {
            if (workFlow.StepSequenceList == null)
                workFlow.GetAllStepSequenceList();

            var nextStepList = new List<RuntimeStepSequence>();
            var step = workFlow.StepSequenceList.Where(w => w.PreviousId == "0").FirstOrDefault();
            workFlow.RuntimeWorkFlow.Status = "Runing";
            workFlow.RuntimeWorkFlow.UpdataTime = DateTime.Now;

            var temp = ConvertStepToRuntimeStep(workFlow.RuntimeWorkFlow.Id, step, null, null);
            temp.HandlingTime = DateTime.Now;
            if (temp.StepType == "Single")
                temp.Status = "待处理";
            else
                temp.Status = "自动";
            temp.NextId = null;
            temp.StepType = "Single";
            temp.RecordTime = DateTime.Now;
            temp.CurrentHandlerType = UserName;
            temp.CurrentHandlerId = UserId;

            nextStepList.Add(temp);
            workFlow.AddRuntimeWorkFlow(nextStepList);
            workFlow.getRuntimeWorkFlow(workFlow.RuntimeWorkFlow.Id); // 刷新列表
            OnRun?.Invoke(null, new WorkFlowEventArgs(steps: nextStepList));
        }

        /// <summary>
        /// 根据当前步骤，查找出下一步。下一步有可能是多个并行启动的步骤。
        /// </summary>
        /// <param name="workFlow"></param>
        /// <returns></returns>
        private static List<StepSequence> getNextRunStepSequence(this WorkFlow workFlow, RuntimeStepSequence currenRunStep)
        {
            var nextStepList = new List<StepSequence>();
            var definitionStep = workFlow.StepSequenceList.FirstOrDefault(m => m.Id == currenRunStep.StepSequenceId);

            if (definitionStep.StepType == "Single")
            {
                nextStepList.Add(workFlow.StepSequenceList.Where(w => w.Id == definitionStep.NextId).FirstOrDefault());
                return nextStepList;
            }

            if (definitionStep.StepType == "Ioc")
            {
                var list = workFlow.StepSequenceList.Where(w => w.StepName == currenRunStep.StepName && w.StepType == "IocStart");
                foreach (var item in list)
                {
                    nextStepList.Add(item);
                }
                return nextStepList;
            }

            if (definitionStep.StepType == "IocStart" || definitionStep.StepType == "LoopStart" || definitionStep.StepType == "JudgeStart")
            {
                nextStepList.Add(workFlow.StepSequenceList.Where(w => w.Id == definitionStep.NextId).FirstOrDefault());
                return nextStepList;
            }

            if (definitionStep.StepType == "IocEnd") // 如果不需要等待所有分支流程走完就出现分支流程的后续步骤，可以在这里设置一个条件
            {
                var endCount = workFlow.RuntimeStepSequenceList.Count(m => m.StepType == "IocEnd" && m.StepName == definitionStep.StepName);
                var startCount = workFlow.RuntimeStepSequenceList.Count(m => m.StepType == "IocStart" && m.StepName == definitionStep.StepName);

                if (startCount == endCount)
                {
                    var ioc = workFlow.StepSequenceList.FirstOrDefault(m => m.StepType == "Ioc" && m.StepName == definitionStep.StepName);
                    nextStepList.Add(workFlow.StepSequenceList.Where(w => w.Id == ioc.NextId).FirstOrDefault());
                    return nextStepList;
                }
            }

            if (definitionStep.StepType == "Loop")
            {
                var ids = definitionStep.CurrentHandlerId.Split(',');
                var loopStart = workFlow.StepSequenceList.FirstOrDefault(m => m.StepType == "LoopStart" && m.StepName == definitionStep.StepName);
                var branchName = WorkFlow._newId();
                foreach (var id in ids)
                {
                    var newStep = new StepSequence(loopStart);
                    newStep.StepName = branchName;
                    nextStepList.Add(newStep);
                }
                return nextStepList;
            }

            if (definitionStep.StepType == "LoopEnd") // 如果不需要等待所有分支流程走完就出现分支流程的后续步骤，可以在这里设置一个条件
            {
                var endCount = workFlow.RuntimeStepSequenceList.Count(m => m.StepType == "LoopEnd" && m.StepName == currenRunStep.StepName);
                var startCount = workFlow.RuntimeStepSequenceList.Count(m => m.StepType == "LoopStart" && m.StepName == currenRunStep.StepName);

                if (startCount == endCount)
                {
                    var runLoopStart = workFlow.RuntimeStepSequenceList.FirstOrDefault(m => m.StepType == "LoopStart" && m.StepName == currenRunStep.StepName);
                    var runloop = workFlow.RuntimeStepSequenceList.FirstOrDefault(m => m.Id == runLoopStart.PreviousId);
                    var loop = workFlow.StepSequenceList.FirstOrDefault(m => m.Id == runloop.StepSequenceId);
                    nextStepList.Add(workFlow.StepSequenceList.Where(w => w.Id == loop.NextId).FirstOrDefault());
                    return nextStepList;
                }
            }

            if (definitionStep.StepType == "Judge")
            {
                var nextIdList = definitionStep.NextId.Split(',');
                foreach (var id in nextIdList)
                {
                    var judgeStart = workFlow.StepSequenceList.Where(w => w.Id == id).FirstOrDefault();
                    var domain = workFlow.GetDomianClass(workFlow.RuntimeWorkFlow.DomainName, workFlow.RuntimeWorkFlow.DomainId);
                    var expression = workFlow.analysisJudgeExpression(domain, judgeStart.JudgmentConditions);
                    if (getJudgeExpressionValue(workFlow, expression))
                        nextStepList.Add(judgeStart);
                }
            }

            if (definitionStep.StepType == "JudgeEnd")
            {
                var endCount = workFlow.RuntimeStepSequenceList.Count(m => m.StepType == "JudgeEnd" && m.BranchName == currenRunStep.BranchName);
                var startCount = workFlow.RuntimeStepSequenceList.Count(m => m.StepType == "JudgeStart" && m.BranchName == currenRunStep.BranchName);

                if (startCount == endCount)
                {
                    nextStepList.Add(workFlow.StepSequenceList.Where(w => w.Id == definitionStep.NextId).FirstOrDefault());
                    return nextStepList;
                }
            }

            if (definitionStep.StepType == "Convergence")
            {
                nextStepList.Add(workFlow.StepSequenceList.Where(w => w.Id == definitionStep.NextId).FirstOrDefault());
                return nextStepList;
            }

            return nextStepList;
        }

        /// <summary>
        /// 获得绑定类实例
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="workFlow"></param>
        /// <param name="DomainName"></param>
        /// <returns></returns>
        private static object GetDomianClass(this WorkFlow workFlow, string DomainName, string DomainId)
        {
            AssemblyName aName = new AssemblyName(workFlow.RuntimeWorkFlow.AssemblyName);
            Assembly ass = Assembly.Load(aName);
            Type ty = ass.GetType(string.Concat(workFlow.RuntimeWorkFlow.NameSpace, ".", DomainName));
            var obj = Activator.CreateInstance(ty);

            MethodInfo mi = ty.GetMethod("GetInstance");
            var invoke = mi.Invoke(obj, new object[] { DomainId }); //指明该方法需要一个参数。
            return invoke;
        }

        /// <summary>
        /// 撤消当前步骤
        /// </summary>
        /// <param name="workFlow"></param>
        /// <param name="runStepId"></param>
        /// <returns></returns>
        public static void Cancel(this WorkFlow workFlow, string runStepId)
        {
            var run = workFlow.RuntimeStepSequenceList.FirstOrDefault(m => m.Id == runStepId);
            if (run == null)
                return;

            var next = workFlow.RuntimeStepSequenceList.FirstOrDefault(m => m.Id == run.NextId);
            if (next == null || !string.IsNullOrEmpty(next.NextId))
                return;

            run.NextId = null;
            workFlow.RemoveRuntimeStep(next);
            OnCancel?.Invoke(null, new WorkFlowEventArgs(step: next));
        }

        /// <summary>
        /// 退回到指定步骤
        /// </summary>
        /// <param name="workFlow"></param>
        /// <param name="runStepId">当前运行步骤ID</param>
        /// <param name="backStepId">退回到指定步骤的ID，默认为当前步骤的上一步</param>
        /// <param name="handlerType"></param>
        /// <param name="handlerId"></param>
        /// <returns></returns>
        public static void TakeAStepBack(this WorkFlow workFlow, string runStepId, string backStepId = null, string handlerType = null, string handlerId = null)
        {
            var run = workFlow.RuntimeStepSequenceList.FirstOrDefault(m => m.Id == runStepId);
            if (run == null)
                return;

            string id = "";
            if (!string.IsNullOrEmpty(backStepId))
                id = backStepId;
            else
                id = run.PreviousId;

            var pre = workFlow.RuntimeStepSequenceList.FirstOrDefault(m => m.Id == id);
            while (pre.StepType != "Single")
            {
                pre = workFlow.RuntimeStepSequenceList.FirstOrDefault(m => m.Id == pre.PreviousId);
                if (pre == null)
                    return;
            }

            //RunCurrentRunStep(workFlow, run, handlerType, handlerId);
            run.Status = "退回";

            List<StepSequence> nextStepList = new List<StepSequence>();
            nextStepList.Add(workFlow.StepSequenceList.FirstOrDefault(m => m.Id == pre.StepSequenceId));

            string nextIds = "";
            var runNextStepList = StepConvertToRunstep(workFlow, nextStepList, run.Id, out nextIds);

            FollowUpProcessing(workFlow, run, runNextStepList, nextIds);
            workFlow.AddRuntimeWorkFlow(runNextStepList);
            workFlow.getRuntimeWorkFlow(workFlow.RuntimeWorkFlow.Id); // 刷新列表
            OnTakeBack?.Invoke(null, new WorkFlowEventArgs(step: pre));
        }

        /// <summary>
        /// 跳过所有未执行步骤，直接结束流程
        /// </summary>
        /// <param name="workFlow"></param>
        public static void ToEndStep(this WorkFlow workFlow, string Suggestion)
        {
            var currenRunStep = new RuntimeStepSequence();
            currenRunStep = workFlow.RuntimeStepSequenceList.FirstOrDefault(m => m.NextId == null && m.StepType == "Single");

            var nextStepList = new List<WfStepSequence>();
            var endStep = workFlow.StepSequenceList.Where(w => w.PreviousId == "1").FirstOrDefault();
            nextStepList.Add(endStep);

            string nextIds;
            var runNextStepList = StepConvertToRunstep(workFlow, nextStepList, currenRunStep.Id, out nextIds);
            runNextStepList[0].Suggestion = Suggestion;

            FollowUpProcessing(workFlow, currenRunStep, runNextStepList, nextIds);
            workFlow.AddRuntimeWorkFlow(runNextStepList);
            workFlow.getRuntimeWorkFlow(workFlow.RuntimeWorkFlow.Id); // 刷新列表
            workFlow.RunWorkFlow();
        }

        public static event EventHandler<WorkFlowEventArgs> OnCancel;

        public static event EventHandler<WorkFlowEventArgs> OnRun;

        public static event EventHandler<WorkFlowEventArgs> OnTakeBack;
    }

    public class WorkFlowEventArgs : EventArgs
    {
        public List<RuntimeStepSequence> runSteps { get; }

        public WorkFlowEventArgs(RuntimeStepSequence step = null, List<RuntimeStepSequence> steps = null)
        {
            if (steps != null)
                runSteps = steps;
            else
            {
                runSteps = new List<RuntimeStepSequence>();
                runSteps.Add(step);
            }
        }
    }

    /// <summary>
    /// 运行时流程步骤参数类
    /// </summary>
    public class StepParameters
    {
        /// <summary>
        /// 当前处理用户类型
        /// </summary>
        public string CurrentHandlerType { get; set; }

        /// <summary>
        /// 当前处理用户ID
        /// </summary>
        public string CurrentHandlerId { get; set; }

        /// <summary>
        /// 指定附加数据的类型
        /// </summary>
        public string AdditionalType { get; set; }

        /// <summary>
        /// 附加数据 (默认为 Dictionary(string, string) )
        /// </summary>
        public string AdditionalData { get; set; }

    }

    /// <summary>
    /// 启动一个新流程时使用的参数类
    /// </summary>
    public class StarWFParameters
    {
        public string WorkFlowId { get; set; }
        public string DomainName { get; set; }
        public string DomainId { get; set; }
        public string ApprovedByID { get; set; }
        public string ApprovedByName { get; set; }
    }

    /// <summary>
    /// 工作流定义
    /// </summary>
    public partial class WfDefinition
    {
        public string Id { get; set; }

        /// <summary>
        /// 工作流名称
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 流程类型
        /// </summary>
        public string Type { get; set; }

        /// <summary>
        /// 工作流说明
        /// </summary>
        public string Description { get; set; }

        /// <summary>
        /// 工作流创建者 Id
        /// </summary>
        public string CreatorId { get; set; }

        /// <summary>
        /// 是否启用
        /// </summary>
        public bool Enable { get; set; }

        /// <summary>
        /// 创建时间
        /// </summary>
        public DateTime CreatTime { get; set; }

        /// <summary>
        /// 流程版本号，用该数字来区分新旧流程，这样新流程定义不会影响就有流程的运行
        /// </summary>
        public int Version { get; set; }

        public WfDefinition(string id, string name, string description,string type, string creatorId)
        {
            this.Id = id;
            this.Name = name;
            this.Type = type;
            this.Description = description;
            this.CreatorId = creatorId;
            this.Enable = true;
            this.CreatTime = DateTime.Now;
            this.Version = 1;
        }
    }

    public partial class WfStepSequence
    {
        public string Id { get; set; }

        public string DefinitionId { get; set; }

        /// <summary>
        /// 前一步ID，“0” 代表工作流开始
        /// </summary>
        public string PreviousId { get; set; }

        /// <summary>
        /// 下一步ID，“1” 代表工作流结束。如果步骤类型为容器，后续可同时启动多个步骤，“,”分隔ID。
        /// </summary>
        public string NextId { get; set; }

        /// <summary>
        /// 步骤类型，单步 Single，判断 Judge，容器 Ioc，Loop 重复。
        /// 容器是指该步骤包含多个同时启动的后续步骤。
        /// 重复是指有多个后续处理人，进行相同处理的步骤。例如：抄送多人阅示
        /// ？流程可复用
        /// </summary>
        public string StepType { get; set; }

        /// <summary>
        /// 汇聚点名称
        /// ？流程可复用
        /// </summary>
        public string ConvergencePoint { get; set; }

        /// <summary>
        /// 当前处理用户类型
        /// </summary>
        public string CurrentHandlerType { get; set; }

        /// <summary>
        /// 当前处理用户ID，如果是 Loop 类型，这里可以存放多个用户ID。
        /// 凡是在定义时就指定的用户ID，存放在这里。流程中动态获得的用户ID，存放在运行时序列中。
        /// </summary>
        public string CurrentHandlerId { get; set; }

        /// <summary>
        /// 步骤名称，程序运行时系统调用的名称，步骤名称在一个流程中是唯一
        /// </summary>
        public string StepName { get; set; }

        /// <summary>
        /// 步骤说明，解释性文本，可用来做每一步的说明
        /// </summary>
        public string Description { get; set; }

        /// <summary>
        /// 当前步骤所属层级
        /// </summary>
        public int Level { get; set; }

        /// <summary>
        /// 如果有子流程，这里是子流程入口。如果并发多个子流程，用逗号分开
        /// </summary>
        public string SubProcess { get; set; }

        /// <summary>
        /// 判断条件表达式
        /// </summary>
        public string JudgmentConditions { get; set; }

        /// <summary>
        /// 流程版本号，用该数字来区分新旧流程，这样新流程定义不会影响就有流程的运行
        /// </summary>
        public int? Version { get; set; }

        public WfStepSequence() { }

        public WfStepSequence(string id, string definitionId, string stepType, string convergencePoint, string stepName, string description, string currentHandlerType, string currentHandlerId, string previousId, string nextId, int Level, string subProcess, string judgmentConditions, int? version)
        {
            this.Id = id;
            this.DefinitionId = definitionId;
            this.StepType = stepType;
            this.ConvergencePoint = convergencePoint;
            this.StepName = stepName;
            this.Description = description;
            this.CurrentHandlerType = currentHandlerType;
            this.CurrentHandlerId = currentHandlerId;
            this.PreviousId = previousId;
            this.NextId = nextId;
            this.Level = Level;
            this.SubProcess = subProcess;
            this.JudgmentConditions = judgmentConditions;
            this.Version = version;
        }

        public WfStepSequence(WfStepSequence step)
        {
            this.Id = step.Id;
            this.DefinitionId = step.DefinitionId;
            this.StepType = step.StepType;
            this.ConvergencePoint = step.ConvergencePoint;
            this.StepName = step.StepName;
            this.Description = step.Description;
            this.CurrentHandlerType = step.CurrentHandlerType;
            this.CurrentHandlerId = step.CurrentHandlerId;
            this.PreviousId = step.PreviousId;
            this.NextId = step.NextId;
            this.Level = step.Level;
            this.SubProcess = step.SubProcess;
            this.JudgmentConditions = step.JudgmentConditions;
            this.Version = step.Version;
        }
    }

    public partial class WfRuntimeWorkFlow
    {
        public string Id { get; set; }

        public string DefinitionId { get; set; }

        /// <summary>
        /// 创建者
        /// </summary>
        public string CreaterId { get; set; }

        /// <summary>
        /// 创建者类型
        /// </summary>
        public string CreaterType { get; set; }

        public DateTime? CreateTime { get; set; }

        /// <summary>
        /// 流程状态，草稿Draft、运行中Runing、结束Finish。草稿可以保存编辑状态，不做检查，发起时才检查。
        /// </summary>
        public string Status { get; set; }

        /// <summary>
        /// 状态更新时间
        /// </summary>
        public DateTime? UpdataTime { get; set; }

        /// <summary>
        /// 流程绑定的领域名称
        /// </summary>
        public string DomainName { get; set; }

        /// <summary>
        /// 流程绑定的程序集名称
        /// </summary>
        public string AssemblyName { get; set; }

        /// <summary>
        /// 流程绑定的命名空间名称
        /// </summary>
        public string NameSpace { get; set; }

        /// <summary>
        /// 流程绑定的领域ID
        /// </summary>
        public string DomainId { get; set; }

        /// <summary>
        /// 流程版本号，用该数字来区分新旧流程，这样新流程定义不会影响就有流程的运行
        /// </summary>
        public int? Version { get; set; }

        public WfRuntimeWorkFlow(string definitionId, string createrType, string createrId, string domainName, string assemblyName, string nameSpace, string domainId, int? version)
        {
            this.Id = WorkFlow._newId();
            this.DefinitionId = definitionId;
            this.CreaterType = createrType;
            this.CreaterId = createrId;
            this.CreateTime = DateTime.Now;
            this.Status = "Draft";
            this.UpdataTime = DateTime.Now;
            this.DomainName = domainName;
            this.AssemblyName = assemblyName;
            this.NameSpace = nameSpace;
            this.DomainId = domainId;
            this.Version = version;
        }
    }

    public partial class WfRuntimeStepSequence
    {
        public string Id { get; set; }

        public string RuntimeWorkFlowId { get; set; }

        public string StepSequenceId { get; set; }

        /// <summary>
        /// 前一步ID，0 代表工作流开始
        /// </summary>
        public string PreviousId { get; set; }

        /// <summary>
        /// 下一步ID，“1” 代表工作流结束，后续可同时启动多个步骤，“,”分隔ID。
        /// </summary>
        public string NextId { get; set; }

        /// <summary>
        /// 当前处理用户类型 或 用户名
        /// </summary>
        public string CurrentHandlerType { get; set; }

        /// <summary>
        /// 当前处理用户ID
        /// </summary>
        public string CurrentHandlerId { get; set; }

        /// <summary>
        /// 步骤类型  Single/Ioc/Loop/Judge
        /// </summary>
        public string StepType { get; set; }

        /// <summary>
        /// 步骤名称，程序运行时系统调用的名称
        /// </summary>
        public string StepName { get; set; }

        /// <summary>
        /// 分支名称，如果是 判断分支 标识当前步骤所处分支起点的步骤名称。
        /// 如果是 loop 节点，标识内部并行流程的起点 LoopStart 的 Id
        /// </summary>
        public string BranchName { get; set; }

        /// <summary>
        /// 描述
        /// </summary>
        public string Description { get; set; }

        /// <summary>
        /// 指定附加数据的类型
        /// </summary>
        public string AdditionalType { get; set; }

        /// <summary>
        /// 附加数据 ((默认为 Dictionary(string, string) )),附加数据中可以定义下一步步骤的操作人
        /// </summary>
        public string AdditionalData { get; set; }

        /// <summary>
        /// 处理意见
        /// </summary>
        public string Suggestion { get; set; }

        /// <summary>
        /// 该步骤状态，待处理，正常，自动，退回，撤消
        /// </summary>
        public string Status { get; set; }

        /// <summary>
        /// 记录时间
        /// </summary>
        public DateTime? RecordTime { get; set; }

        /// <summary>
        /// 处理时间
        /// </summary>
        public DateTime? HandlingTime { get; set; }

        /// <summary>
        /// 当前步骤所属层级
        /// </summary>
        public int? Level { get; set; }

        public WfRuntimeStepSequence() { }

        public WfRuntimeStepSequence(string runtimeWorkFlowId, WfStepSequence stepSequence, string previousId = null, string nextId = null)
        {
            this.Id = WorkFlow._newId();
            this.RuntimeWorkFlowId = runtimeWorkFlowId;
            this.StepSequenceId = stepSequence.Id;
            if (previousId != null)
                this.PreviousId = previousId;
            else
                this.PreviousId = stepSequence.PreviousId;
            if (nextId != null)
                this.NextId = nextId;
            else
                this.NextId = stepSequence.NextId;
            this.CurrentHandlerType = stepSequence.CurrentHandlerType;
            this.CurrentHandlerId = stepSequence.CurrentHandlerId;

            if (stepSequence.StepType == "Convergence" || stepSequence.StepType == "JudgeEnd" || stepSequence.StepType == "JudgeStart")
                this.BranchName = stepSequence.ConvergencePoint;

            this.StepName = stepSequence.StepName;
            this.BranchName = stepSequence.ConvergencePoint;
            this.Description = stepSequence.Description;
            this.Level = stepSequence.Level;
            this.StepType = stepSequence.StepType;
        }
    }
}
